package com.visionblue.business.ship.page.collection

import android.util.Log
import androidx.lifecycle.MutableLiveData
import com.jakewharton.disklrucache.DiskLruCache
import com.visionblue.business.ship.base.BaseRepository
import com.visionblue.business.ship.model.Results
import com.visionblue.business.ship.model.bean.local.OilFlowInfo
import com.visionblue.business.ship.model.bean.local.UltraSonicFlowInfo
import com.visionblue.business.ship.model.bean.local.WaterFlowInfo
import com.visionblue.business.ship.model.bean.request.PostApplicationRequest
import com.visionblue.business.ship.model.bean.response.ApplicationDetail
import com.visionblue.business.ship.model.enums.WasteTypeEnum
import com.visionblue.business.ship.model.repository.DeviceInfoRepository
import com.visionblue.business.ship.model.repository.RemoteRepository
import com.visionblue.business.ship.model.repository.db.*
import com.visionblue.business.ship.page.register.config.OIL_VOLUME_NAME
import com.visionblue.business.ship.page.register.config.WATER_VOLUME_NAME
import com.visionblue.business.ship.page.register.config.WEIGHT_NAME
import com.visionblue.business.ship.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.math.abs

/**
 * @author: xlh
 * @date: 2020-05-19 2:27 PM
 * @desc:
 */
class CollectionRepository(
    private val collectionRecordDao: CollectionRecordDao,
    private val cachedOrderDao: CachedOrderDao,
    private val recordAndOrderDao: RecordAndOrderDao,
    private val diskLruCache: DiskLruCache,
    private val deviceInfoRepository: DeviceInfoRepository
) :
    BaseRepository() {

    val recordsLiveData = MutableLiveData<MutableList<CollectionRecord>>(mutableListOf())

    private var weightWorkingRecord: CollectionRecord? = null
    private var waterRecord: CollectionRecord? = null
    private var wasteWaterRecord: CollectionRecord? = null
    private var oilRecord: CollectionRecord? = null
    private var ultraRecord: CollectionRecord? = null

    fun createLocalRecordInMemory(
        wasteTypeEnum: WasteTypeEnum,
        startTime: Long,
        menuItem: MeasureMenuItem
    ) {
        val record = CollectionRecord(wasteTypeEnum.code,"", 0f, null, startTime, null)
        record.alias = menuItem.alias
        when {
            menuItem.isSolid() -> {
                weightWorkingRecord = record
            }
            menuItem.isOil() -> {
                oilRecord = record
            }
            menuItem.isUltraSonic() -> {
                ultraRecord = record
            }
            menuItem.isWater() -> {
                waterRecord = record
            }
            menuItem.isWasteWater()-> {
                wasteWaterRecord = record
            }
//            wasteTypeEnum.isOil() || wasteTypeEnum == WasteTypeEnum.OIL_UNDEFINE -> {
//
//                record.alias = menuItems.find { it.isOil() }?.alias
//            }
//            wasteTypeEnum.isWater() || wasteTypeEnum == WasteTypeEnum.WATER_UNDEFINE -> {
//                waterRecord = record
//                record.alias = menuItems.find { it.isWater() }?.alias
//            }
//            wasteTypeEnum == WasteTypeEnum.ULTRA_UNDEFINE -> {
//                ultraRecord = record
//                record.alias = menuItems.find { it.isUltraSonic() }?.alias
//            }

//            wasteTypeEnum == WasteTypeEnum.OIL_UNDEFINE -> {
//                oilRecord = record
//                record.alias = menuItems.find { it.name == OIL_VOLUME_NAME }?.alias
//            }
//            wasteTypeEnum == WasteTypeEnum.WATER_UNDEFINE -> {
//                waterRecord = record
//            }
        }


        val recordsInMemory = recordsLiveData.value ?: mutableListOf()
        recordsInMemory.add(0, record)
        MLog.e("createLocalRecordInMemory: $recordsInMemory")
        recordsLiveData.value = recordsInMemory

//        if (wasteType == WasteTypeEnum.SOLID_WASTE.code) {
//            weightWorkingRecord = record
//        } else {
//            flowWorkingRecord = record
//        }
    }

    fun updateOilWeight(initOilFlowInfo: OilFlowInfo?, currOilFlowInfo: OilFlowInfo) {
        if (initOilFlowInfo == null) {
            return
        }
        val recordsInMemory = recordsLiveData.value
        if (recordsInMemory != null) {
            oilRecord?.originWeight =
                FormatUtils.format3Decimal(abs(currOilFlowInfo.positiveAccumulationVal - initOilFlowInfo.positiveAccumulationVal))
                    .toFloat()
            oilRecord?.accumulationFlowUnit =  currOilFlowInfo.accumulationFlowUnit  // 油没有累计单位,写死
            recordsLiveData.postValue(recordsInMemory)
        }
    }

    fun updateWaterWeight(initWaterFlowInfo: WaterFlowInfo?, currWaterFlowInfo: WaterFlowInfo) {
        if (initWaterFlowInfo == null) {
            return
        }
        val recordsInMemory = recordsLiveData.value
        if (recordsInMemory != null && recordsInMemory.isNotEmpty()) {
            Log.e("===>","123")
            waterRecord?.originWeight =
                FormatUtils.format3Decimal(abs(currWaterFlowInfo.positiveAccumulationVal - initWaterFlowInfo.positiveAccumulationVal))
                    .toFloat()
            waterRecord?.accumulationFlowUnit =  currWaterFlowInfo.accumulationFlowUnit
           /* waterRecord?.originWeight =
                    FormatUtils.format3Decimal(abs(0.05))
                            .toFloat()*/
            recordsLiveData.postValue(recordsInMemory)
        }
    }

    fun updateWasteWaterWeight(initWaterFlowInfo: WaterFlowInfo?, currWaterFlowInfo: WaterFlowInfo) {
        if (initWaterFlowInfo == null) {
            return
        }
        val recordsInMemory = recordsLiveData.value
        if (recordsInMemory != null && recordsInMemory.isNotEmpty()) {
            wasteWaterRecord?.originWeight =
                FormatUtils.format3Decimal(abs(currWaterFlowInfo.positiveAccumulationVal - initWaterFlowInfo.positiveAccumulationVal))
                    .toFloat()

            wasteWaterRecord?.accumulationFlowUnit =  currWaterFlowInfo.accumulationFlowUnit
            recordsLiveData.postValue(recordsInMemory)
        }
    }

    fun updateSonicWeight(
        initSonicFlowInfo: UltraSonicFlowInfo?,
        currSonicFlowInfo: UltraSonicFlowInfo
    ) {
        if (initSonicFlowInfo == null) return

        val recordsInMemory = recordsLiveData.value
        if (recordsInMemory != null && recordsInMemory.isNotEmpty()) {
            ultraRecord?.originWeight =
                FormatUtils.format3Decimal(abs(currSonicFlowInfo.positiveAccumulationVal - initSonicFlowInfo.positiveAccumulationVal))
                    .toFloat()

            ultraRecord?.accumulationFlowUnit =  currSonicFlowInfo.accumulationFlowUnit //  超声波没有累计单位,写固定
            recordsLiveData.postValue(recordsInMemory)
        }
    }

    private suspend fun insertFlowRecord(
        cachedOrder: CachedOrder,
        flowWorkingRecord: CollectionRecord?
    ) {
        val recordsInMemory = recordsLiveData.value
        if (recordsInMemory != null && recordsInMemory.isNotEmpty() && flowWorkingRecord != null) {
            if (flowWorkingRecord.endTime == null) {
                flowWorkingRecord.endTime = System.currentTimeMillis()
                flowWorkingRecord.cachedOrderId = cachedOrder.id
                val results = collectionRecordDao.insert(flowWorkingRecord)
                if (results.isNotEmpty() && results[0] != -1L) {
                    flowWorkingRecord.id = results[0]
                }
                recordsLiveData.value = recordsInMemory
            }
        }
    }

    suspend fun insertWaterRecord(cachedOrder: CachedOrder) {
        insertFlowRecord(cachedOrder, waterRecord)
    }

    suspend fun insertWasteWaterRecord(cachedOrder: CachedOrder) {
        insertFlowRecord(cachedOrder, wasteWaterRecord)
    }

    suspend fun insertOilRecord(cachedOrder: CachedOrder) {
        insertFlowRecord(cachedOrder, oilRecord)
    }

    suspend fun insertSonicRecord(cachedOrder: CachedOrder) {
        insertFlowRecord(cachedOrder, ultraRecord)
    }

    suspend fun insertWeightRecord(weight: Int, cachedOrder: CachedOrder, wasteType: String) {
        val collectionRecord = CollectionRecord(
            wasteType,
                "",
            originWeight = weight.toFloat(),
            startTime = System.currentTimeMillis(),
            endTime = System.currentTimeMillis(),
            cachedOrderId = cachedOrder.id
        )
        val results = collectionRecordDao.insert(collectionRecord)
        if (results.isNotEmpty() && results[0] != -1L) {
            collectionRecord.id = results[0]
        }
        val records = recordsLiveData.value
        records?.add(collectionRecord)
        recordsLiveData.value = records
    }

    suspend fun loadCollectionRecords(cachedOrder: CachedOrder) {

        val records =
            getCollectionRecordsFromDB(cachedOrder)

        withContext(Dispatchers.Main) {
            if (records != null) {
                val list = recordsLiveData.value
                if (list == null || list.isEmpty()) {
                    recordsLiveData.value = (records.toMutableList())
                } else {
                    list.removeAll(records)
                    list.addAll(records)
                    recordsLiveData.value = list
                }
            }
        }
    }

    suspend fun getCollectionRecordsFromDB(cachedOrder: CachedOrder): List<CollectionRecord>? {
        return recordAndOrderDao.getAllCachedOrderWithCollectionRecords(deviceInfoRepository.sn)
            .find { cachedOrder.id == it.cachedOrder.id }
            ?.records
            ?.sortedByDescending { it.startTime }
    }

    suspend fun deleteRecord(record: CollectionRecord) {
        collectionRecordDao.delete(record)
        val records = recordsLiveData.value
        records?.remove(record)
        recordsLiveData.value = records
    }

    suspend fun submit(id: String, request: PostApplicationRequest): Results<String> {
        return safeApiCall(call = { RemoteRepository.postApplication(id, request) })
    }

    suspend fun deleteCachedOrderById(id: Long?) {
        if (id == null) return
        recordAndOrderDao.getCachedOrderWithCollectionRecordsByOrderId(id).let {
            collectionRecordDao.delete(*it.records.toTypedArray())
            cachedOrderDao.delete(it.cachedOrder)
        }
    }

    suspend fun insertCachedOrder(cachedOrder: CachedOrder) {
        cachedOrderDao.insert(cachedOrder)
        cachedOrder.id = cachedOrderDao.getAll().maxBy { it.id!! }?.id
    }

    suspend fun updateCachedOrder(
        cachedOrder: CachedOrder,
        endTime: Long? = null,
        companyName: String? = null,
        applicationId: String? = null
    ) {

        // 并没有创建记录  直接返回
        if (cachedOrder.id == null) {
            return
        }

        if (endTime != null) {
            cachedOrder.endTime = endTime
        }

        if (companyName != null) {
            cachedOrder.companyName = companyName
        }

        if (applicationId != null) {
            cachedOrder.applicationId = applicationId
        }

        cachedOrderDao.update(cachedOrder)
    }

    suspend fun queryCachedOrderById(cachedOrderId: Long): CachedOrder {
        return cachedOrderDao.getOrderById(cachedOrderId)
    }

//    suspend fun getApplicationDetail(applicationId: String): Results<ApplicationDetail> {
//        return safeApiCall(call = { RemoteRepository.getApplicationDetail(applicationId) })
//    }

    fun cacheApplicationDetail(
        cachedOrderId: Long,
        detail: ApplicationDetail
    ) {
        val key = MD5Util.md5(cachedOrderId.toString())
        val json = GsonProvider.gson().toJson(detail)
        val editor = diskLruCache.edit(key)
        editor.set(0, json)
        editor.commit()
    }

    fun getCachedApplicationDetail(cachedOrderId: Long?): ApplicationDetail? {
        if (cachedOrderId == null) return null

        val key = MD5Util.md5(cachedOrderId.toString())
        val json = diskLruCache.get(key)?.getString(0)
        if (json != null && JSONUtil.isJSONValid(json)) {
            return GsonProvider.gson().fromJson(json, ApplicationDetail::class.java)
        }

        return null
    }

    suspend fun updateCollectionRecord(record: CollectionRecord) {
        collectionRecordDao.update(record)
    }

    suspend fun getWeightRecordByCachedOrderId(cachedOrderId: Long?): CollectionRecord? {
        if (cachedOrderId == null) return null
        return recordAndOrderDao.getCachedOrderWithCollectionRecordsByOrderId(cachedOrderId).records.find { it.wasteType == WasteTypeEnum.SOLID_WASTE.code }
    }

    suspend fun findCachedOrderByApplicationId(applicationId: String): CachedOrder? {
        return cachedOrderDao.findOrderByApplicationId(applicationId)
    }

    suspend fun addNotRecordToFlow(
        weight: Float,
        wasteTypeEnum: WasteTypeEnum,
        cachedOrder: CachedOrder
    ) {
        val collectionRecord = CollectionRecord(
            wasteTypeEnum.code,
                "",
            weight,
            null,
            System.currentTimeMillis(),
            System.currentTimeMillis(),
            cachedOrder.id
        )

        val results = collectionRecordDao.insert(collectionRecord)

        if (results.isNotEmpty() && results[0] != -1L) {
            collectionRecord.id = results[0]
        }

        recordsLiveData.value = recordsLiveData.value?.apply {
            add(0, collectionRecord)
        }
    }

//    suspend fun addNotRecordToOil(
//        weight: Float,
//        cachedOrder: CachedOrder
//    ) {
//        val collectionRecord = CollectionRecord(
//            WasteTypeEnum.OIL_UNDEFINE.code,
//            weight,
//            null,
//            System.currentTimeMillis(),
//            System.currentTimeMillis(),
//            cachedOrder.id
//        )
//
//        val results = collectionRecordDao.insert(collectionRecord)
//
//        if (results.isNotEmpty() && results[0] != -1L) {
//            collectionRecord.id = results[0]
//        }
//
//        recordsLiveData.value = recordsLiveData.value?.apply {
//            add(0, collectionRecord)
//        }
//    }

}